package ru.dc;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import ru.dc.object.CommandListener;
import ru.dc.object.commands.Command;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Vector;

/**
 * Created by IntelliJ IDEA.
 * User: deady
 * Date: 31.10.2010
 * Time: 12:27:15
 */
public class CommandDispatchingThread extends Thread {


    private static final CommandDispatchingThread instance = new CommandDispatchingThread();
    final private List<Command> commandQueue = new Vector<Command>();
    private boolean stopRequested= false;
    private Vector<CommandListener> commandListeners = new Vector<CommandListener>();
    private Log logger = LogFactory.getLog(getClass());
    private static final int SLEEP_AMOUNT = 50;

    private final Object lock = new Object();

    public void addCommand(Command command) {
        synchronized (lock) {
            commandQueue.add(command);
            lock.notifyAll();
        }
        logger.trace("Added command: "+command);
    }

    public void addCommands(Collection<Command> commands) {
        synchronized (lock) {
            commandQueue.addAll(commands);
            lock.notifyAll();
        }
        logger.trace("Added "+commands.size()+" commands");
    }

    @Override
    public void run() {
        while (!stopRequested) {
            Collection<Command> commands;

            synchronized (lock) {
                if (commandQueue.isEmpty()) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        logger.error("Error while wating commands: "+e.getMessage(), e);
                    }
                }
                commands = new ArrayList<Command>(commandQueue);
                commandQueue.clear();

            }
            if (!commands.isEmpty()) {
                for (Command c : commands) {
                    try {
                        c.parseCommand();
                    } catch (Exception e) {
                        logger.error("Can't parse command: "+c, e);
                    }
                    dispatchCommand(c);
                }
            }
        }
        logger.info("*** Stopped");
    }

    public void addCommandListener(CommandListener listener) {
        commandListeners.add(listener);
    }

    public void removeCommandListener(CommandListener listener) {
        commandListeners.remove(listener);
    }

    private void dispatchCommand(Command command) {
        logger.trace("Dispatching command: "+command);
        for (CommandListener listener : commandListeners) {
            listener.commandRecieved(command);
        }
    }

    public static CommandDispatchingThread getInstance() {
        return instance;
    }

    public void requestStop() {
        stopRequested = true;
    }
}
